/* 
 * File:   Triangle.cpp
 * Author: brady
 * 
 * Created on February 4, 2011, 11:15 PM
 */

#include "Triangle.h"


Triangle::Triangle() {
    Vector3D p1, p2, p3;
    p1 = Vector3D(0.0, 0.0, 0.0);
    p2 = Vector3D(1.0, 0.0, 0.0);
    p3 = Vector3D(1.0, 1.0, 0.0);
    Triangle(p1, p2, p3);
    type = "Triangle";
}

Triangle::Triangle(Vector3D p1, Vector3D p2, Vector3D p3)
{
    this->P1 = p1;
    this->P2 = p2;
    this->P3 = p3;
    Vector3D E1 = P2 - P1;
    Vector3D E2 = P3 - P2;
    normal = E1.cross(E2);
    normal.normalize();
    double xmin = min(P1[0], min(P2[0], P3[0]));
    double xmax = max(P1[0], max(P2[0], P3[0]));
    double ymin = min(P1[1], min(P2[1], P3[1]));
    double ymax = max(P1[1], max(P2[1], P3[1]));
    double zmin = min(P1[2], min(P2[2], P3[2]));
    double zmax = max(P1[2], max(P2[2], P3[2]));
    boundingBox = new BoundingBox(xmin, xmax, ymin, ymax, zmin, zmax);
    SetShader(new LambertianShader());
    type = "Triangle";
}

Triangle::~Triangle() {
}

bool Triangle::TestIntersect(Ray &ray, double tmin, double tmax, HitStruct& hitStruct)
{
    double a, b, c, d, e, f, g, h, i;
    double j, k, l;
    double beta, gamma, t;
    Vector3D orig = ray.GetOrigin();
    Vector3D dir = ray.GetDirection();

    a = P1[0]-P2[0];
    b = P1[1]-P2[1];
    c = P1[2]-P2[2];
    d = P1[0]-P3[0];
    e = P1[1]-P3[1];
    f = P1[2]-P3[2];
    g = -1.0* dir[0];
    h = -1.0* dir[1];
    i = -1.0* dir[2];
    j = P1[0]- orig[0];
    k = P1[1]- orig[1];
    l = P1[2]- orig[2];

    double M = a*(e*i-h*f)+b*(g*f-d*i)+c*(d*h-e*g);

    t = (f*(a*k-j*b)+e*(j*c-a*l)+d*(b*l-k*c))/M;
    if(t<tmin | t > tmax)
    {
        return false;
    }
    gamma = (i*(a*k-j*b)+h*(j*c-a*l)+g*(b*l-k*c))/M;
    if(gamma < 0 | gamma > 1)
    {
        return false;
    }
    beta = (j*(e*i-h*f)+k*(g*f-d*i)+l*(d*h-e*g))/M;
    if(beta < 0 | beta > (1-gamma))
    {
        return false;
    }
    else
    {
        hitStruct.tVal = t;
        hitStruct.shader = this->shader;
        hitStruct.normal = this->normal;

        return true;

    }
}



//const Vector3D Triangle::SurfaceNormal(Ray &ray)
//{
////    if(ray.GetDirection().dot(normal) < 0.0)
////    {
////        return normal * -1.0;
////    }
////    else return normal;
//    return normal;
//}

double Triangle::GetSortValue(int sortBy)
{
    return (P1[sortBy] + P2[sortBy] + P3[sortBy])/3.0;
}
